/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.simple;

import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.GetListRequestMessage;
import cn.easyplatform.messages.request.MapRequestMessage;
import cn.easyplatform.messages.vos.GetListVo;
import cn.easyplatform.messages.vos.component.ListMapVo;
import cn.easyplatform.messages.vos.component.ListPageVo;
import cn.easyplatform.messages.vos.component.MapVo;
import cn.easyplatform.messages.vos.datalist.ListGetListVo;
import cn.easyplatform.spi.service.ComponentService;
import cn.easyplatform.type.FieldVo;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.ext.ComponentBuilder;
import cn.easyplatform.web.ext.zul.Wandbox;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.zkex.ListSupport;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.event.EventListenerHandler;
import cn.easyplatform.web.task.zkex.list.PanelSupport;
import cn.easyplatform.web.utils.PageUtils;
import cn.easyplatform.web.utils.WebUtils;
import org.apache.commons.lang3.StringUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlNativeComponent;
import org.zkoss.zk.ui.event.*;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.*;
import org.zkoss.zul.event.PagingEvent;
import org.zkoss.zul.event.ZulEvents;

import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
@SuppressWarnings("unchecked")
public class WandboxBuilder implements ComponentBuilder, EventListener<Event> {

    private OperableHandler main;

    private Wandbox wb;

    private ListSupport support;

    private Component anchor;

    private Listbox listbox;

    private String value;

    private EventListener<Event> elh;

    private boolean singleSign = true;

    public WandboxBuilder(OperableHandler mainTaskHandler, Wandbox ab) {
        this.main = mainTaskHandler;
        this.wb = ab;
    }

    public WandboxBuilder(ListSupport support, Wandbox ab, Component anchor) {
        this.support = support;
        this.main = support.getMainHandler();
        this.wb = ab;
        this.anchor = anchor;
    }

    @Override
    public Component build() {
        PageUtils.checkAccess(main.getAccess(), wb);
        if (!Strings.isBlank(wb.getQuery())) {
            if (!Strings.isBlank(wb.getEvent()))
                wb.addEventListener(Events.ON_CHANGE, this);
            wb.addEventListener(Events.ON_CHANGING, this);
            wb.setCtrlKeys("#down@1@2");
            wb.addEventListener(Events.ON_CTRL_KEY, this);
            wb.addEventListener(Events.ON_OPEN, this);
            Bandpopup bp = new Bandpopup();
            if (!Strings.isBlank(wb.getPanelHeight()))
                bp.setHeight(wb.getPanelHeight());
            if (!Strings.isBlank(wb.getPanelWidth()))
                bp.setWidth(wb.getPanelWidth());
            else
                bp.setWidth("450px");
            if (!Strings.isBlank(wb.getOffsetX()))
                bp.setLeft(wb.getOffsetX());
            wb.appendChild(bp);
        }
        if (!Strings.isBlank(wb.getEvent())) {
            if (support != null) {
                elh = (EventListener<Event>) wb
                        .getEventListeners(Events.ON_CHANGE).iterator().next();
                wb.removeEventListener(Events.ON_CHANGE, elh);
            } else
                elh = new EventListenerHandler(Events.ON_CHANGE, main, wb.getEvent(), anchor);
        }
        return wb;
    }

    private void createContent(String value) throws Exception {
        this.value = value;
        ComponentService cs = ServiceLocator
                .lookup(ComponentService.class);
        GetListVo gv = null;
        if (anchor != null) {
            ListRowVo rowVo = WebUtils.getAnchorValue(anchor);
            Object[] data = support.isCustom() ? rowVo.getData() : rowVo
                    .getKeys();
            gv = new ListGetListVo(wb.getDbId(), wb.getQuery(), support
                    .getComponent().getId(), data);
        } else if (main instanceof PanelSupport) {
            ListSupport ls = ((PanelSupport) main).getList();
            gv = new ListGetListVo(wb.getDbId(), wb.getQuery(), ls
                    .getComponent().getId(), null);
        } else
            gv = new GetListVo(wb.getDbId(), wb.getQuery());
        gv.setFilter(wb.getFilter());
        gv.setPageSize(wb.getPageSize());
        gv.setOrderBy(wb.getOrderBy());
        gv.setGetCount(true);
        int count = StringUtils.countMatches(gv.getQuery(), "?");
        if (gv.getParameters() != null)
            gv.getParameters().clear();
        if (value.equals("")) {
            for (int i = 0; i < count; i++)
                gv.setParameter("%");
        } else {
            String[] prefix = new String[count];
            String[] suffix = new String[count];
            for (int i = 0; i < count; i++) {
                prefix[i] = "%";
                suffix[i] = "%";
            }
            if (wb.getPrefix() != null) {
                String[] tmp = wb.getPrefix().split(",");
                int len = tmp.length > count ? count : tmp.length;
                for (int i = 0; i < len; i++)
                    prefix[i] = tmp[i];
            }
            if (wb.getSuffix() != null) {
                String[] tmp = wb.getSuffix().split(",");
                int len = tmp.length > count ? count : tmp.length;
                for (int i = 0; i < len; i++)
                    suffix[i] = tmp[i];
            }
            for (int i = 0; i < count; i++)
                gv.setParameter(prefix[i] + value + suffix[i]);
        }
        GetListRequestMessage req = new GetListRequestMessage(main.getId(), gv);
        IResponseMessage<?> resp = cs.getList(req);
        if (resp.isSuccess()) {
            if (resp.getBody() instanceof List<?>) {
                List<FieldVo[]> list = (List<FieldVo[]>) resp.getBody();
                if (!list.isEmpty()) {
                    // if (list.size() == 1) {
                    // setValue(list.get(0));
                    // } else {
                    createComponents(-1, list.get(0).length);// 没分页
                    draw(list);
                    // }
                }
            } else {
                ListPageVo pv = (ListPageVo) resp.getBody();
                if (!pv.getData().isEmpty()) {
                    // if (pv.getData().size() == 1) {
                    // setValue(pv.getData().get(0));
                    // } else {
                    createComponents(pv.getTotalCount(),
                            pv.getData().get(0).length);
                    draw(pv.getData());
                    // }
                }
            }
        } else
            Clients.wrongValue(wb, (String) resp.getBody());
    }

    private void paging(int pageNo) {
        ComponentService cs = ServiceLocator
                .lookup(ComponentService.class);
        GetListVo gv = null;
        if (anchor != null) {
            ListRowVo rowVo = WebUtils.getAnchorValue(anchor);
            Object[] data = support.isCustom() ? rowVo.getData() : rowVo
                    .getKeys();
            gv = new ListGetListVo(wb.getDbId(), wb.getQuery(), support
                    .getComponent().getId(), data);
        } else if (main instanceof PanelSupport) {
            ListSupport ls = ((PanelSupport) main).getList();
            gv = new ListGetListVo(wb.getDbId(), wb.getQuery(), ls
                    .getComponent().getId(), null);
        } else
            gv = new GetListVo(wb.getDbId(), wb.getQuery());
        gv.setFilter(wb.getFilter());
        gv.setPageSize(wb.getPageSize());
        gv.setOrderBy(wb.getOrderBy());
        gv.setPageNo(pageNo);
        gv.setGetCount(false);
        int count = StringUtils.countMatches(gv.getQuery(), "?");
        if (gv.getParameters() != null)
            gv.getParameters().clear();
        if (value.equals("")) {
            for (int i = 0; i < count; i++)
                gv.setParameter("%");
        } else {
            String[] prefix = new String[count];
            String[] suffix = new String[count];
            for (int i = 0; i < count; i++) {
                prefix[i] = "%";
                suffix[i] = "%";
            }
            if (wb.getPrefix() != null) {
                String[] tmp = wb.getPrefix().split(",");
                int len = tmp.length > count ? count : tmp.length;
                for (int i = 0; i < len; i++)
                    prefix[i] = tmp[i];
            }
            if (wb.getSuffix() != null) {
                String[] tmp = wb.getSuffix().split(",");
                int len = tmp.length > count ? count : tmp.length;
                for (int i = 0; i < len; i++)
                    suffix[i] = tmp[i];
            }
            for (int i = 0; i < count; i++)
                gv.setParameter(prefix[i] + value + suffix[i]);
        }
        GetListRequestMessage req = new GetListRequestMessage(main.getId(), gv);
        IResponseMessage<?> resp = cs.getList(req);
        if (resp.isSuccess()) {
            List<FieldVo[]> list = (List<FieldVo[]>) resp.getBody();
            draw(list);
        } else
            Clients.wrongValue(wb, (String) resp.getBody());
    }

    private void createComponents(int totalCount, int columns) {
        if (listbox == null) {
            listbox = new Listbox();
            listbox.addEventListener(Events.ON_OK, this);
            listbox.addEventListener(Events.ON_CANCEL, this);
            listbox.setCtrlKeys("@1@2");
            listbox.addEventListener(Events.ON_CTRL_KEY, this);
            Listhead head = new Listhead();
            if (!Strings.isBlank(wb.getTitle())) {
                head.setSizable(wb.isSizable());
                String[] headers = wb.getTitle().split(",");
                for (String h : headers) {
                    Listheader header = new Listheader(h.trim());
                    header.setHflex("1");
                    head.appendChild(header);
                }
                columns = headers.length;
            } else {
                for (int i = 0; i < columns; i++) {
                    Listheader header = new Listheader();
                    head.appendChild(header);
                }
            }
            listbox.appendChild(head);
        } else if (listbox.getListfoot() != null)
            listbox.getListfoot().detach();
        if (totalCount > wb.getPageSize()) {// 有分页
            Paging paging = null;
            Listfoot foot = new Listfoot();
            Listfooter footer = new Listfooter();
            footer.setParent(foot);
            footer.setSpan(columns);
            paging = new Paging(totalCount, wb.getPageSize());
            paging.setHflex("1");
            paging.setStyle(wb.getPagingStyle());
            paging.setMold(wb.getPagingMold());
            paging.setDetailed(wb.isPagingDetailed());
            paging.setPageSize(wb.getPageSize());
            paging.setParent(footer);
            paging.addEventListener(ZulEvents.ON_PAGING, this);
            listbox.appendChild(foot);
        }
        listbox.setParent(wb.getDropdown());
    }

    @Override
    public void onEvent(Event event) throws Exception {
        if (event.getName().equals(Events.ON_CHANGE)) {
            if ((listbox == null || listbox.getParent() == null))
                elh.onEvent(event);
        } else if (event.getName().equals(ZulEvents.ON_PAGING)) {
            PagingEvent evt = (PagingEvent) event;
            paging(evt.getActivePage() + 1);
        } else if (event.getName().equals(Events.ON_OPEN)) {
            OpenEvent oe = (OpenEvent) event;
            if (!oe.isOpen() && listbox != null) {
                listbox.detach();
            } else if (wb.getDropdown().getFirstChild() == null)
                createContent((String) oe.getValue());
        } else if (event.getName().equals(Events.ON_CANCEL)) {
            wb.setFocus(true);
            wb.close();
            listbox.detach();
        } else if (event.getName().equals(Events.ON_CTRL_KEY)) {
            KeyEvent ke = (KeyEvent) event;
            if (ke.getKeyCode() == 49 || ke.getKeyCode() == 50) {
                if (listbox.getListfoot() != null) {
                    Paging pg = (Paging) listbox.getListfoot().getFirstChild()
                            .getFirstChild();
                    int pageNo = pg.getActivePage();
                    if (ke.getKeyCode() == 49) {
                        if (pageNo == 0)
                            return;
                        pageNo--;
                    } else {
                        if (pageNo == pg.getPageCount() - 1)
                            return;
                        pageNo++;
                    }
                    pg.setActivePage(pageNo);
                    paging(pageNo + 1);
                }
            } else if (listbox != null) {
                if (listbox.getItemCount() > 0) {
                    if (ke.getKeyCode() == 0) {// 其实是13回车键
                        FieldVo[] fvs = listbox.getItemAtIndex(0).getValue();
                        setValue(fvs);
                    } else
                        listbox.getItemAtIndex(0).setFocus(true);
                }
            }
        } else if (event.getName().equals(Events.ON_DOUBLE_CLICK)
                || event.getName().equals(Events.ON_OK)) {
            if (listbox.getSelectedCount() > 0) {
                Contexts.setEvent(Event.class, new Event(
                        Events.ON_CLICK, wb));
                try {
                    FieldVo[] fvs = listbox.getSelectedItem().getValue();
                    setValue(fvs);
                    wb.setFocus(true);
                    wb.setSelectionRange(0, wb.getValue().length());
                } finally {
                    Contexts.clear();
                }
            }
        } else {
            InputEvent ie = (InputEvent) event;
            if (wb.getDropdown().getFirstChild() != null)
                wb.getDropdown().getFirstChild().detach();
            createContent(ie.getValue().trim());
        }
    }

    private void setValue(FieldVo[] fvs) throws Exception {
        Object oValue = wb.getRawValue();
        Object nValue = null;
        if (Strings.isBlank(wb.getMapping())) {
            if (Strings.isBlank(wb.getValueField()))
                nValue = fvs[0].getValue();
            else {
                for (FieldVo fv : fvs) {
                    if (fv.getName().equals(wb.getValueField())) {
                        nValue = fv.getValue();
                        break;
                    }
                }
            }
        } else {
            ComponentService cs = ServiceLocator
                    .lookup(ComponentService.class);
            MapVo mv = null;
            Map<String, Component> managedComponents = null;
            if (anchor != null) {
                ListRowVo rowVo = WebUtils.getAnchorValue(anchor);
                Object[] data = support.isCustom() ? rowVo.getData() : rowVo
                        .getKeys();
                mv = new ListMapVo(wb.getMapping(), fvs, support.getComponent()
                        .getId(), data);
                managedComponents = WebUtils.getManagedComponents(support, anchor);
            } else if (main instanceof PanelSupport) {
                ListSupport ls = ((PanelSupport) main).getList();
                mv = new ListMapVo(wb.getMapping(), fvs, ls.getComponent()
                        .getId(), null);
                managedComponents = support.getManagedPanelComponents();
            } else {
                mv = new MapVo(wb.getMapping(), fvs);
                managedComponents = main.getManagedComponents();
            }
            IResponseMessage<?> resp = cs.doMap(new MapRequestMessage(main
                    .getId(), mv));
            if (resp.isSuccess()) {
                Map<String, Object> data = (Map<String, Object>) resp.getBody();
                for (Map.Entry<String, Object> entry : data.entrySet()) {
                    Component c = managedComponents.get(entry.getKey());
                    if (c != null) {
                        if (c == wb)
                            nValue = entry.getValue();
                        else {
                            Object o = PageUtils.getValue(c,
                                    false);
                            if (!Lang.equals(o, entry.getValue())) {
                                PageUtils.setValue(c,
                                        entry.getValue());
                                Event evt = new Event(Events.ON_CHANGE,
                                        c);
                                Events.sendEvent(c, evt);
                            }
                        }
                    }
                }
            } else
                Clients.wrongValue(wb, (String) resp.getBody());
        }
        String val = nValue == null ? "" : nValue.toString();
        if (!Lang.equals(oValue, val)) {
            wb.setValue(val);
            if (elh != null)
                elh.onEvent(new Event(Events.ON_CHANGE, wb));
        }
        wb.close();
        if (listbox != null)
            listbox.detach();
    }

    private void draw(List<FieldVo[]> list) {
        listbox.getItems().clear();
        for (FieldVo[] fvs : list) {
            Listitem li = new Listitem();
            li.setValue(fvs);
            for (int i = 0; i < fvs.length; i++) {
                Listcell c = new Listcell(fvs[i].getValue() == null ? ""
                        : fvs[i].getValue().toString());
                c.setParent(li);
            }
            li.setParent(listbox);
            li.addEventListener(Events.ON_DOUBLE_CLICK, this);
        }
        listbox.getItemAtIndex(0).setSelected(true);
        if(!Strings.isBlank(wb.getOffsetX())) {
            addPopupPosition();
            Clients.evalJavaScript("changePopupPosition()");
        }
        if (!wb.isOpen())
            wb.open();
    }

    private void addPopupPosition(){
        if(singleSign) {
            HtmlNativeComponent cssComponent = new HtmlNativeComponent();
            String css = ".z-bandbox-popup-custom-position{left:"+wb.getOffsetX()+" !important;}";
            cssComponent.setTag("style");
            cssComponent.setStubonly(true);
            cssComponent.setPrologContent(css);
            wb.getRoot().appendChild(cssComponent);
            HtmlNativeComponent scriptComponent = new HtmlNativeComponent();
            String script =
                    "   function changePopupPosition() {" +
                        "   setTimeout(function () {" +
                    "           $(\"#" + wb.getUuid() + "-pp\").addClass(\"z-bandbox-popup-custom-position\");" +
                    "       },50)" +
                    "   };";
            scriptComponent.setTag("script");
            scriptComponent.setStubonly(true);
            scriptComponent.setPrologContent(script);
            wb.getRoot().appendChild(scriptComponent);
            singleSign = false;
        }
    }


}
